package com.py.androidUtils.UI.view;

import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;

/**
 * @说明 富文本编辑器
 * @作者 LY
 * @文件 RichEditor.java
 * @时间 2015年7月22日 上午9:52:46
 */
public class RichEditor extends WebView {

	public enum Type {
		BOLD, ITALIC, SUBSCRIPT, SUPERSCRIPT, STRIKETHROUGH, UNDERLINE, H1, H2, H3, H4, H5, H6
	}

	public interface OnTextChangeListener {

		void onTextChange(String text);
	}

	public interface OnDecorationStateListener {

		void onStateChangeListener(String text, List<Type> types);
	}

	public interface AfterInitialLoadListener {

		void onAfterInitialLoad(boolean isReady);
	}

	private static final String SETUP_HTML = "file:///android_res/raw/editor.html";
	private static final String CALLBACK_SCHEME = "re-callback://";
	private static final String STATE_SCHEME = "re-state://";
	private boolean isReady = false;
	private String mContents;
	private OnTextChangeListener mTextChangeListener;
	private OnDecorationStateListener mDecorationStateListener;
	private AfterInitialLoadListener mLoadListener;

	public RichEditor(Context context) {
		this(context, null);
	}

	public RichEditor(Context context, AttributeSet attrs) {
		this(context, attrs, android.R.attr.webViewStyle);
	}

	public RichEditor(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		setVerticalScrollBarEnabled(false);
		setHorizontalScrollBarEnabled(false);
		getSettings().setJavaScriptEnabled(true);
		setWebChromeClient(new WebChromeClient());
		setWebViewClient(new WebViewClient() {
			@Override
			public void onPageFinished(WebView view, String url) {
				isReady = url.equalsIgnoreCase(SETUP_HTML);
				if (mLoadListener != null) {
					mLoadListener.onAfterInitialLoad(isReady);
				}
			}

			@Override
			public boolean shouldOverrideUrlLoading(WebView view, String url) {
				String decode;
				try {
					decode = URLDecoder.decode(url, "UTF-8");
				} catch (Exception e) {
					// No handling
					return false;
				}

				if (TextUtils.indexOf(url, CALLBACK_SCHEME) == 0) {
					callback(decode);
					return true;
				} else if (TextUtils.indexOf(url, STATE_SCHEME) == 0) {
					stateCheck(decode);
					return true;
				}

				return super.shouldOverrideUrlLoading(view, url);
			}
		});
		loadUrl(SETUP_HTML);
	}

	public void setOnTextChangeListener(OnTextChangeListener listener) {
		mTextChangeListener = listener;
	}

	public void setOnDecorationChangeListener(OnDecorationStateListener listener) {
		mDecorationStateListener = listener;
	}

	public void setOnInitialLoadListener(AfterInitialLoadListener listener) {
		mLoadListener = listener;
	}

	private void callback(String text) {
		mContents = text.replaceFirst(CALLBACK_SCHEME, "");
		if (mTextChangeListener != null) {
			mTextChangeListener.onTextChange(mContents);
		}
	}

	private void stateCheck(String text) {
		String state = text.replaceFirst(STATE_SCHEME, "").toUpperCase(Locale.ENGLISH);
		List<Type> types = new ArrayList<Type>();
		for (Type type : Type.values()) {
			if (TextUtils.indexOf(state, type.name()) != -1) {
				types.add(type);
			}
		}

		if (mDecorationStateListener != null) {
			mDecorationStateListener.onStateChangeListener(state, types);
		}
	}

	public void setEditorFontSize(int px) {
		exec("javascript:RE.setFontSize('" + px + "px');");
	}

	public void setHtml(String contents) {
		if (contents == null) {
			contents = "";
		}
		try {
			exec("javascript:RE.setHtml('" + URLEncoder.encode(contents, "UTF-8") + "');");
		} catch (Exception e) {
			// No handling
		}
		mContents = contents;
	}

	public String getHtml() {
		return mContents;
	}

	public void setEditorBackgroundColor(int color) {
		String hex = convertHexColorString(color);
		exec("javascript:RE.setBackgroundColor('" + hex + "');");
	}

	public void setEditorWidth(int px) {
		exec("javascript:RE.setWidth('" + px + "px');");
	}

	public void setEditorHeight(int px) {
		exec("javascript:RE.setHeight('" + px + "px');");
	}

	public void setPlaceholder(String placeholder) {
		exec("javascript:RE.setPlaceholder('" + placeholder + "');");
	}

	public void loadCSS(String cssFile) {
		String jsCSSImport = "(function() {" + "    var head  = document.getElementsByTagName(\"head\")[0];" + "    var link  = document.createElement(\"link\");" + "    link.rel  = \"stylesheet\";" + "    link.type = \"text/css\";" + "    link.href = \"" + cssFile + "\";" + "    link.media = \"all\";" + "    head.appendChild(link);" + "}) ();";
		exec("javascript:" + jsCSSImport + "");
	}

	public void undo() {
		exec("javascript:RE.undo();");
	}

	public void redo() {
		exec("javascript:RE.redo();");
	}

	public void setBold() {
		exec("javascript:RE.setBold();");
	}

	public void setItalic() {
		exec("javascript:RE.setItalic();");
	}

	public void setSubscript() {
		exec("javascript:RE.setSubscript();");
	}

	public void setSuperscript() {
		exec("javascript:RE.setSuperscript();");
	}

	public void setStrikeThrough() {
		exec("javascript:RE.setStrikeThrough();");
	}

	public void setUnderline() {
		exec("javascript:RE.setUnderline();");
	}

	public void setTextColor(int color) {
		exec("javascript:RE.prepareInsert();");

		String hex = convertHexColorString(color);
		exec("javascript:RE.setTextColor('" + hex + "');");
	}

	public void setTextBackgroundColor(int color) {
		exec("javascript:RE.prepareInsert();");

		String hex = convertHexColorString(color);
		exec("javascript:RE.setTextBackgroundColor('" + hex + "');");
	}

	public void setHeading(int heading) {
		exec("javascript:RE.setHeading('" + heading + "');");
	}

	public void setIndent() {
		exec("javascript:RE.setIndent();");
	}

	public void setOutdent() {
		exec("javascript:RE.setOutdent();");
	}

	public void setAlignLeft() {
		exec("javascript:RE.setJustifyLeft();");
	}

	public void setAlignCenter() {
		exec("javascript:RE.setJustifyCenter();");
	}

	public void setAlignRight() {
		exec("javascript:RE.setJustifyRight();");
	}

	public void setBlockquote() {
		exec("javascript:RE.setBlockquote();");
	}

	public void insertImage(String url, String alt) {
		exec("javascript:RE.prepareInsert();");
		exec("javascript:RE.insertImage('" + url + "', '" + alt + "');");
	}

	public void insertLink(String href, String title) {
		exec("javascript:RE.prepareInsert();");
		exec("javascript:RE.insertLink('" + href + "', '" + title + "');");
	}

	public void focusEditor() {
		requestFocus();
		exec("javascript:RE.focus();");
	}

	public void clearFocusEditor() {
		exec("javascript:RE.blurFocus();");
	}

	private String convertHexColorString(int color) {
		return String.format("#%06X", (0xFFFFFF & color));
	}

	private void exec(String trigger) {
		if (isReady) {
			load(trigger);
		} else {
			new waitLoad(trigger).execute();
		}
	}

	@SuppressLint("NewApi")
	private void load(String trigger) {
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
			evaluateJavascript(trigger, null);
		} else {
			loadUrl(trigger);
		}
	}

	private class waitLoad extends AsyncTask<Void, Void, Void> {

		private String mTrigger;

		public waitLoad(String trigger) {
			super();
			mTrigger = trigger;
		}

		@Override
		protected Void doInBackground(Void... params) {
			while (!RichEditor.this.isReady) {
				sleep(100);
			}
			return null;
		}

		@Override
		protected void onPostExecute(Void aVoid) {
			load(mTrigger);
		}

		private synchronized void sleep(long ms) {
			try {
				wait(ms);
			} catch (InterruptedException ignore) {
			}
		}
	}
}
